<?php

error_reporting( E_ALL ); //you WANT this !
// ----------- PHP COMPAT
if ( ! defined( 'DIRECTORY_SEPARATOR' )) define( DIRECTORY_SEPARATOR, strtoupper(substr(PHP_OS,0,3)=='WIN')?'\\':'/' );

include( 'classes/path.php' );
include( 'classes/content-controller.php' );

class CacheOnRequest 
{
	var $uri = null; //uri requested
	var $basePath = null; //base path of generated images
	
	var $tokens = null; //array containing tokenized request
	
	var $configuration = array(
		  'excludeDirs' => array( '_libs', '_did', '.svn', '.cvs' )
		, 'allowedFileExtensions' => array( 'jpg', 'png', 'gif' )
		, 'redirectToContent' => true //if false, outputs the log, else it redirects to the image
		, 'debug' => false //shows debug log (also disabled if redirectToContent is enabled
		, 'stopGeneration' => false //only for debug obv
		//enabling this can lead to damage, accidental deletion of hard disk. Beware !
		// when disabled it makes php die() when any error (notices or greater) happens.
		//this is because an simple mistype when working with files could lead a filesystem path's  variable 
		//to become empty and make the class reference root directory.
		//a better solution is (of course) well set permissions, btw this is not always possible for
		//the average (windows-based) developer 
		, 'continueOnError' => false 
		, 'driversPath' => 'controllers'
	);
	function CacheOnRequest( $globalDebug = false )
	{
		if ( $globalDebug === false || $globalDebug === 0 )
		{
			$this->configuration['debug']=false; 
			$this->configuration['stopGeneration']=false;
		}
		if ( $globalDebug === 1 ) //shows problems on error
		{
			$this->configuration['debug']=true; 
			$this->configuration['stopGeneration']=false;
		}
		if ( $globalDebug === 2 || $globalDebug === true ) //shows logs anyway, hinibits file generation
		{
			$this->configuration['debug']=true; 
			$this->configuration['stopGeneration']=true;
			$this->configuration['redirectToContent']=false;
		}
		
		$this->_autoIncludeDrivers();
	}
	function run ( $uri, $basePath )
	{
		ob_start();
		$this->_debugInit();		
		$this->uri = $uri; unset ( $uri );
		$this->basePath = $basePath;
		$DocumentRoot = new Path( $_SERVER[ 'DOCUMENT_ROOT' ], null );
		$this->documentRoot = $DocumentRoot->normalized(); //for retrieving source
		
		lll ( 'current uri: '. $this->uri );
		lll ( 'current basePath: '. $this->basePath );
		lll ( 'current documentRoot: '. $this->documentRoot );
		lll ( 'current configuration', $this->configuration );
			
		//------- analyzing
		$this->analyzeRequest( $this->uri );
		
		$result = $this->runDrivers( $this->tokens );
		
		ob_end_flush();
	}
	function runDrivers ( $tokens )
	{
		foreach ( array_keys( $this->drivers) as $key )
		{
			$Driver =& $this->drivers[ $key ];
			$result = $Driver->run( $tokens );
			
			if ( $result === true )
			{
				lll ( 'Driver '.get_class( $Driver ).' accepted and completed generation request.');
				break;
			}
			if ( is_null( $result ))
			{
				lll ( 'Driver '.get_class( $Driver ).' skipped or processed only part of request.');
			}
			if ( is_array( $result ))
			{
				$tokens = $result;
				lll ( 'Driver '.get_class( $Driver ).' processed part of request and updated URI to: '.$this->_tokens2path( $tokens ));
			}
			if ( $result === false )
			{
				lll ( 'Driver '.get_class( $Driver ).' asked stop of all processing. Aborting.');
				break;
			}
		}
	}
	function analyzeRequest ( $uri )
	{
		lll ( '---- analyzing '.$uri );
		
		$this->tokens = $this->_getTokens( $uri );
		
		lll( 'request tokens:', $this->tokens );
	}
	function _tokensDiff ( $tokens, $base )
	{
		foreach ( $base as $baseToken )
		{
			if ( array_shift( $tokens ) !== $baseToken ) return false;
		}
		return $tokens;
	}
	function _getTokens ( $uri )
	{
		$myBase = $this->_path2tokens( dirname( $_SERVER[ 'PHP_SELF' ] ));
		$tokens = $this->_path2tokens( $uri );
		return $this->_tokensDiff( $tokens, $myBase );
	}
	function _tokens2path ( $tokens )
	{
		return join( '/', $tokens );
	}
	function _path2tokens ( $uri )
	{
		
		$parsedUri = parse_url( $uri );
		$uri = $parsedUri[ 'path' ];
		$uri = trim( $uri, '/' );
		$tokens = explode( '/', $uri );
		
		return $tokens;
	}
	function _debugInit()
	{
		if ( $this->configuration[ 'debug' ] ) Logger::printScreen( true ); //comment out to disable screen logging
		Logger::progressiveFlush( false ); //avoid problem when sending headers
		if ( ! $this->configuration[ 'continueOnError' ] )
		{
			set_error_handler( array( $this , 'errorHandler'));
		}
	}
	
	//---------------- drivers
	function _autoIncludeDrivers ()
	{
		$driversPath = $this->_normalizePathToAbsolute( $this->configuration[ 'driversPath' ], dirname( __FILE__ ) );
		if ( ! file_exists($driversPath ) )
		{
			trigger_error ( "driver path '{$this->configuration[ 'driversPath' ]}' ('$driversPath') not found, aborting ");
			die;
		}
		$driversFiles = $this->_fileList( $driversPath );
		asort( $driversFiles );
		foreach ( $driversFiles as $file ) include_once ( $file );
	}
	function attachDriver ( &$Driver )
	{
//		$this->driver = new ImageResizer ();
		$Driver->setController( &$this );
		$this->drivers[] =& $Driver;
		
	}
	
	//---------- errorhandling
	
	function errorHandler ( $errno, $errstr, $errfile, $errline )
	{
		if ( $errno > E_ALL ) return false;
		if ( !$errno ) return false;
		$codes = array(
			E_NOTICE => 'E_NOTICE', 
			E_WARNING => 'E_WARNING', 
			E_ERROR => 'E_ERROR', 
			E_USER_ERROR => 'E_USER_ERROR', 
			E_USER_WARNING => 'E_USER_WARNING', 
			E_USER_NOTICE => 'E_USER_NOTICE'
		);
		
		if ( key_exists( $errno, $codes )) $errno = $codes[ $errno ];
		$args =  array( $errno, 'message' => $errstr, 'file' => $errfile, 'line' =>$errline);
		
		if ( error_reporting() === 0 )
		{
			 lll ( 'Error on a @-prepended function. Continuing. Error details:.',$args );
			 return false;
		}
		
		 lll ( 'Error Caught ! Aborting for security purpouses.',$args );
		 ob_flush();
		die;
	}
	//---------- tokens and files handling ---------
	
	function tokens2SourceFilename( $tokens )
	{
		$Path = $this->_getPathObj( join( '/', $tokens ), $this->documentRoot ); //cabled
		return $Path->absolute();
	}
	function tokens2DestinationFilename( $tokens )
	{
		$Path = $this->_getPathObj( join( '/', $tokens ), $this->basePath );
		return $Path->absolute();
	}
	//---------- filesystem utils
	
	function _normalizePathToAbsolute ( $relativePath, $basePath = false )
	{
		$Path = $this->_getPathObj( $relativePath, $basePath );
		return $Path->absolute();
	}
	function _normalizePath( $relativePath )
	{
		$Path = $this->_getPathObj( $relativePath );
		return $Path->normalized();
	}
	function _fileList( $path )
	{
		$entries = $this->_pathEntries( $path );
		if ( $entries === false ) return false;
		foreach ( $entries as $k => $entry )
		{
			if ( !is_file( $entry )) unset( $entries[ $k ] );
		}
		return $entries;
	}
	function _dirList( $path )
	{
		$entries = $this->_pathEntries( $path );
		if ( $entries === false ) return false;
		foreach ( $entries as $k => $entry )
		{
			if ( !is_dir( $entry )) unset( $entries[ $k ] );
		}
		return $entries;
	}
	function _pathEntries ( $path )
	{
		$path = $this->_normalizePath( $path );
		$entries = array();
		if ( ! file_exists( $path ))
		{
			lll ( 'reading attempt at path: "'.$path.'" failed. Path doesn\'t exists' );
			return false;
		}
		$CurrentDir = dir( $path );
		while (false !== ($entry = $CurrentDir->read())) 
		{
			$fullEntryName = $path.DIRECTORY_SEPARATOR.$entry;
			if ( $entry != '..' && $entry != '.' )
			{
				$entries[] = $fullEntryName;
				if ( is_dir( $fullEntryName ) )
				{
				} elseif ( is_file( $fullEntryName ))
				{
				}
			} else {
//				$this->log( $fullEntryName.' [r]' );
			}
		}
		$CurrentDir->close();
		return $entries;
	}
	function _getPathObj ( $path, $basePath = false)
	{
		if ( $basePath === false ) $basePath = $this->basePath;
		return new Path( $path, $basePath );
	}
}

/**
 * 
 * Sample usage
 * 
 * Copy this package into /dynamic directory of your website.<br />
*  write a in the browser http://[site.com]/dynamic/320x200/yourimagefolder/yourimagesubfolder/image.jpg
* after that... refresh again.
 * 
 * NOTES: 
 * - overwrite renderImage() function to implement our own resize handling
 * - if DIRECTORY_SEPARATOR is not defined we will attempt to set it.
*
 * @todo 
 * Known problems: 
 * 	- using more parameters
 * 	- staticalling images from many folders with the same name
 * 		workaround .. ?
 * 	- symlinks anywhere along document root path make everything fall.
 * To implement:
 * 	- reset mechanism for the singleimage. via the /reset/ param
 */

class GenerateOnRequest
{
	var $configuration = array(
		  'excludeDirs' => array( '_libs', '_did', '.svn', '.cvs' )
		, 'allowedFileExtensions' => array( 'jpg', 'png', 'gif' )
		, 'redirectToContent' => true //if false, outputs the log, else it redirects to the image
		, 'debug' => false //shows debug log (also disabled if redirectToContent is enabled
		, 'stopGeneration' => false //only for debug obv
		//enabling this can lead to damage, accidental deletion of hard disk. Beware !
		// when disabled it makes php die() when any error (notices or greater) happens.
		//this is because an simple mistype when working with files could lead a filesystem path's  variable 
		//to become empty and make the class reference root directory.
		//a better solution is (of course) well set permissions, btw this is not always possible for
		//the average (windows-based) developer 
		, 'continueOnError' => false 
		, 'driversPath' => 'drivers'
	);
	
	var $uri = null; //uri requested
	var $basePath = null; //base path of generated images
	var $vars = array();
	
	var $ref = array();
	
	var $drivers = array(); //stack of attached controllers
	
	/**
	 * Enter description here...
	 *
	 * @param mixed $globalDebug 0/false doesn't show anything, (int)1 shows log on error, 2/true hinibits filegeneration
	 * @return GenerateOnRequest
	 */
	function GenerateOnRequest( $globalDebug = false )
	{
		if ( $globalDebug === false || $globalDebug === 0 )
		{
			$this->configuration['debug']=false; 
			$this->configuration['stopGeneration']=false;
		}
		if ( $globalDebug === 1 ) //shows problems on error
		{
			$this->configuration['debug']=true; 
			$this->configuration['stopGeneration']=false;
		}
		if ( $globalDebug === 2 || $globalDebug === true ) //shows logs anyway, hinibits file generation
		{
			$this->configuration['debug']=true; 
			$this->configuration['stopGeneration']=true;
			$this->configuration['redirectToContent']=false;
		}
		
		$this->_autoIncludeDrivers();
	}
	
	function _autoIncludeDrivers ()
	{
		$driversPath = $this->_normalizePathToAbsolute( $this->configuration[ 'driversPath' ], dirname( __FILE__ ) );
		$driversFiles = $this->_fileList( $driversPath );
		asort( $driversFiles );
		foreach ( $driversFiles as $file ) include_once ( $file );
	}
	function attachDriver ( &$Driver )
	{
//		$this->driver = new ImageResizer ();
		$Driver->setController( &$this );
		$this->drivers[] =& $Driver;
		
	}
	function errorHandler ( $errno, $errstr, $errfile, $errline )
	{
		if ( $errno > E_ALL ) return false;
		if ( !$errno ) return false;
		$codes = array(
			E_NOTICE => 'E_NOTICE', 
			E_WARNING => 'E_WARNING', 
			E_ERROR => 'E_ERROR', 
			E_USER_ERROR => 'E_USER_ERROR', 
			E_USER_WARNING => 'E_USER_WARNING', 
			E_USER_NOTICE => 'E_USER_NOTICE'
		);
		
		if ( key_exists( $errno, $codes )) $errno = $codes[ $errno ];
		$args =  array( $errno, 'message' => $errstr, 'file' => $errfile, 'line' =>$errline);
		
		if ( error_reporting() === 0 )
		{
			 lll ( 'Error on a @-prepended function. Continuing. Error details:.',$args );
			 return false;
		}
		
		 lll ( 'Error Caught ! Aborting for security purpouses.',$args );
		 ob_flush();
		die;
	}
	
	function _normalizeExclusionList ()
	{
		foreach ( $this->configuration[ 'excludeDirs' ] as $k => $dir )
		{
			$dir = $this->_normalizePathToAbsolute( $dir );
			$this->configuration[ 'excludeDirs' ][ $k ]	= $dir;
		}		
//		lll( 'list of current excluded dirs:', $this->configuration[ 'excludeDirs' ] );
	}
	/**
	 * Exists from the flow with a die();
	 */
	function _permissionDenied()
	{
		die( 'permission denied' );
	}
	/**
	 * Process the request.
	 * 
	 * This methos will try to generate the requested file and then attempt to redirect user to the generated file.
	 *
	 * @param string $uri request uri
	 * @param string $basePath base path where to put  generated images. Must be writable from php
	 */
	
	function run ( $uri, $basePath )
	{
		ob_start();
		if ( $this->configuration[ 'debug' ] ) Logger::printScreen( true ); //comment out to disable screen logging
		Logger::progressiveFlush( false ); //avoid problem when sending headers
		
		if ( ! $this->configuration[ 'continueOnError' ] )
		{
			set_error_handler( array( $this , 'errorHandler'));
		}
		$this->uri = $uri; unset ( $uri );
		$this->basePath = $basePath;
		$this->_normalizeExclusionList();
		
		lll ( 'current configuration', $this->configuration );
		
		// ----------- PHP COMPAT
		if ( ! defined( 'DIRECTORY_SEPARATOR' )) define( DIRECTORY_SEPARATOR, strtoupper(substr(PHP_OS,0,3)=='WIN')?'\\':'/' );
		//-------------INCLUSIONS
		
		//let's override error document's 404 response
		header("HTTP/1.0 200 OK");
		if ( strpos ( $this->uri, '?again' ) ) //loops prevention
		{
			$this->uri = str_replace( '?again', '', $this->uri);
			$this->configuration[ 'redirectToContent' ] = false;
		}
		$this->vars = $this->_urlProcess();
		
		lll ( 'DIRECTORY_SEPARATOR', DIRECTORY_SEPARATOR );
		lll ( 'sniffed vars', $this->vars );
		
		if ( ! $this->_securityCheck())
		{
			$this->_permissionDenied();
		}

		$pathCreated = $this->createPath ( $this->basePath, $this->vars[ 'neededPath' ] );
		lll ( 'path created? '. $pathCreated );
		$imagePath = $this->basePath;
		
		
		foreach ( array_keys( $this->drivers) as $key )
		{
			$Driver =& $this->drivers[ $key ];
			$generated = $Driver->process( $this->vars[ 'sourceFilename' ], $this->vars[ 'destinationFilename' ], $this->vars[ 'params' ] );
			if ( $generated )
			{
				lll ( 'Driver '.get_class( $Driver ).' accepted and completed generation request.');
				break;
			}
			if ( is_null( $generated ))
			{
				lll ( 'Driver '.get_class( $Driver ).' skipped or processed only part of request.');
			}
			if ( $generated === false )
			{
				lll ( 'Driver '.get_class( $Driver ).' asked stop of all processing. Aborting.');
				break;
			}
		}
		if ( $generated && $this->configuration[ 'redirectToContent' ] )
		{
			header( 'Location: '.$_SERVER[ 'REQUEST_URI' ].'?again' );
			//lll( 'redirecting to the image:'.$_SERVER[ 'REQUEST_URI' ]);
			ob_flush();
			ob_clean();
		} else {
			lll ( 'no redirection. end of process.');
			ob_get_flush();	
		}
	}
	/**
	 * This will parse current uri and try to sniff everything possible (source-name, destination-name etc)
	 * 
	 * Everything will be path into $this->vars
	 *
	 * @return unknown
	 */
	function _urlProcess ()
	{
		$path =$this->uri;
		
		if ( strpos( $path, $this->basePath ) === 0 ) str_replace( $this->basePath , '', $path);
		
		$path = $this->_normalizePath( $path );
		
		$documentRoot = $this->_normalizePath( $_SERVER[ 'DOCUMENT_ROOT' ] );
		
		$pathFromRoot = str_replace($documentRoot, '',  $this->basePath );
		$query = str_replace( $pathFromRoot, '', $path );
		$query = ltrim( $query, DIRECTORY_SEPARATOR );
		$params = explode( DIRECTORY_SEPARATOR, $query );
		$fileName = array_pop( $params );
		
		$neededPath =  join( DIRECTORY_SEPARATOR, $params );
		
		//------------ source filename
		$sourceFilename = $params;
		array_shift( $sourceFilename ); //first parameter is the actual command
		$sourceFilename = $documentRoot . DIRECTORY_SEPARATOR . join( DIRECTORY_SEPARATOR, $sourceFilename ) . DIRECTORY_SEPARATOR . $fileName;
		$sourceFileExists = file_exists( $sourceFilename );
		
		$destinationPath =$this->basePath. DIRECTORY_SEPARATOR. join ( DIRECTORY_SEPARATOR, $params );
		$destinationFilename = $destinationPath. DIRECTORY_SEPARATOR .$fileName;
		
		//for clearness
		/* needed
		- destinationFile (precise)
			- basePath
		- action tokens: diffed from (/dynamic) base URL 
		- destinationBasePath (should concide with base URL)
		
		- sourceFIle
			- needs a base ( documentRoot )
		*/
		$DocumentRoot = $this->_getPathObj( $_SERVER[ 'DOCUMENT_ROOT' ], $this->basePath );
		$DestinationFilename = $this->_getPathObj( join ( DIRECTORY_SEPARATOR, $params ), $this->basePath );
		$SourceFilename = $this->_getPathObj( $this->uri );
		$SourceFilename->path = $SourceFilename->merge( $DocumentRoot->absolute() );
		foreach ( get_defined_vars() as $k => $u )
		{
			if ( is_object( $$k ))
			{
				$this->ref[ $k ] = $u;
				unset ( $$k );
			}
		}
		unset ( $destinationPath, $query, $pathFromRoot );
		unset( $k, $u );
		
		lll ( 'references:', $this->ref );
		return get_defined_vars();
	}
	
	//-------------------------------- FUNCTIONS
	function isExcludedDir ( $fileName )
	{
		$File = $this->_getPathObj( $fileName );
		foreach ( $this->configuration[ 'excludeDirs' ] as $excludedPath )
		{	
			if ( $File->isInside( $excludedPath) )
			{
				lll( 'Called dir "'. $excludedPath .'" is in the exclusion list.');
				return true;
			}
			
		}
		return false;
		/*
		foreach ( $this->configuration[ 'excludeDirs' ] as $excluded )
		{
			if ( substr( $fileName, 0, strlen( $excluded )) == $excluded )
			{
				lll( 'Called dir "'. $dirName .'" is in the exclusion list.');
				return true;
			}
		}
		if ( in_array( $dirName , $this->configuration[ 'excludeDirs' ]))
		{
			lll( 'Called dir "'. $dirName .'" is in the exclusion list.');
			
		}
		return false;
		*/
		
	}
	function _securityCheck ( )
	{
		// hinibits access to libs directorie
		
		if ( $this->isExcludedDir( $this->vars[ 'destinationFilename' ] ) ) return false;
		if ( $this->isExcludedDir( $this->vars[ 'sourceFilename' ] ) ) return false;
		//$fileExtension = $this->_getFileExtension( $this->vars[ 'fileName' ] );
		$Source = $this->_getPathObj( $this->vars[ 'sourceFilename' ] );
		$fileExtension = $Source->extension();
		if ( ! $fileExtension || ! in_array( $fileExtension , $this->configuration[ 'allowedFileExtensions' ]))
		{
			lll( 'Filename "'. $this->vars[ 'fileName' ] .'" must be not-empty, must have an extension and extension has to be inside the allowedFileExtensions list.');
			return false;
		}
		return true;
	}
	function _firstToken ( $haystack, $separator )
	{
		$tokens = explode ( $separator, $haystack );
		return array_shift( $tokens );
	}
	
	//---------------------------- FILESYSTEM FUNCTIONS
	
	function _getPathObj ( $path )
	{
		return new Path( $path, $this->basePath );
	}
	
	// Needs DIRECTORY SEPARATOR already defined
	function createPath ( $basePath, $path )
	{
		if ( $this->configuration['stopGeneration'] )
		{
			lll( "Simulating creation of '$path' ( basepath '$basePath' )");
			return true;
		}
		$basePath = rtrim( $basePath, DIRECTORY_SEPARATOR ). DIRECTORY_SEPARATOR;
		
		$path = ltrim( $path, DIRECTORY_SEPARATOR );
		$tokens = explode( DIRECTORY_SEPARATOR, $path );
		$dirname = array_shift( $tokens );
		
		$created = null;
		$newDirectory = $basePath.$dirname;
		if ( ! is_dir( $newDirectory ))
		{
			$created = mkdir( $newDirectory );
			lll ( 'creating "'.$newDirectory.'": '.$created );
		} else {
			lll ( 'skipping "'.$newDirectory.'"');
		}
		if ( $created === false )
		{
			lll ( 'Could not create '.$newDirectory );
			return false;
		}
		if ( !count( $tokens ))
		{
			lll ( 'Final path created: '.$newDirectory );
			return true;
		} 
		return $this->createPath ( $newDirectory, join( DIRECTORY_SEPARATOR, $tokens ) );
	}
	function _getFileExtension ( $filename )
	{
		$tokens = explode( '.', $filename );
		if ( count( $tokens ) < 2 ) return null;
		return array_pop( $tokens );
	}
	function _normalizePath ( $path )
	{
		if ( DIRECTORY_SEPARATOR != '/' ) $path = str_replace( '/', DIRECTORY_SEPARATOR, $path );
		$path = rtrim( $path );
		return $path;
	}
	function _normalizePathToAbsolute ( $path, $basePath = false )
	{
		if ( $basePath === false ) $basePath = $this->basePath;
		$path = $this->_normalizePath( $path );
		if ( substr( $path, 0, 1 ) != DIRECTORY_SEPARATOR )
		{ 
			//relative path, we assume relative to our base directory
			$path = $basePath.DIRECTORY_SEPARATOR.$path;
		}
		return $path;
	}
	function _fileList( $path )
	{
		$entries = $this->_pathEntries( $path );
		if ( $entries === false ) return false;
		foreach ( $entries as $k => $entry )
		{
			if ( !is_file( $entry )) unset( $entries[ $k ] );
		}
		return $entries;
	}
	function _dirList( $path )
	{
		$entries = $this->_pathEntries( $path );
		if ( $entries === false ) return false;
		foreach ( $entries as $k => $entry )
		{
			if ( !is_dir( $entry )) unset( $entries[ $k ] );
		}
		return $entries;
	}
	function _pathEntries ( $path )
	{
		$path = $this->_normalizePath( $path );
		$entries = array();
		if ( ! file_exists( $path ))
		{
			lll ( 'reading attempt at path: "'.$path.'" failed. Path doesn\'t exists' );
			return false;
		}
		$CurrentDir = dir( $path );
		while (false !== ($entry = $CurrentDir->read())) 
		{
			$fullEntryName = $path.DIRECTORY_SEPARATOR.$entry;
			if ( $entry != '..' && $entry != '.' )
			{
				$entries[] = $fullEntryName;
				if ( is_dir( $fullEntryName ) )
				{
				} elseif ( is_file( $fullEntryName ))
				{
				}
			} else {
//				$this->log( $fullEntryName.' [r]' );
			}
		}
		$CurrentDir->close();
		return $entries;
	}
}

/*======================================================
REMOVED STUFF
=======================================================*/
/* ---evil. removed from main class
	--> inside $this->configuration
		, 'generateDids' => false
	--> inside run()
		// didGeneration is EVIL. When cached files are a lot it can freeze your server
		if ( $generated && $this->configuration[ 'generateDids' ])
		{
			$this->didGenerate( $this->vars[ 'sourceFilename' ], $this->vars );
		}

	
	function didGetPath ( $sourceFilename, $v)
	{
		return 
			$this->basePath
			. DIRECTORY_SEPARATOR
			. '_did'
			 .DIRECTORY_SEPARATOR
			 . urlencode( $sourceFilename );
	}
	function didGenerate ( $sourceFilename, $v )
	{	 
		$didPath = $this->didGetPath( $sourceFilename, $v );
		$mtime = filemtime( $sourceFilename );
		$this->didKill( $sourceFilename, $v );
		lll ( 'generating did for "'.$sourceFilename.'" :'.$mtime);
		lll ( 'didPath: '. $didPath );
		error_log( $mtime, 3, $didPath );
	}
	function didKill  ( $sourceFilename, $v )
	{
		$didPath = $this->didGetPath( $sourceFilename, $v );
		if ( file_exists( $didPath ) )
		{
			lll ( 'killing did for "'.$sourceFilename.'" ');
			return unlink ( $didPath );
		} else {
			lll ( 'no did existant for "'.$sourceFilename.'" ');
		}
		return false;
	}
	*/
?>